'''
Created on Oct 8, 2013

@author: dewey
'''
import os
import sys
import tempfile
import subprocess

from PyQt4.QtCore import *
from PyQt4.QtGui import *
import ui_gen.resources_rc
from qpynygeolib.mapwidgets import LayerManagerListWidget, ScaleOverlayMapFrame, GraphicsMapFrame
from qpynygeolib.maplayers import LayerManager, LayerFactory
from qpynygeolib.sceneprojections import SceneProjections
import geolib.utm as utm
from tilelib.openstreetmap import OpenStreetMapLayerFactory
from tilelib.toporama import ToporamaLayerFactory
import externalreslib.mapquest as mapquest
import qpynygeolib.mapfileIO as mapfileIO
import filelib.kml as kml

from ui_gen.Ui_main_window import Ui_MainWindow

import MeasureDialog
import LayerDataDialog

DIRTY = False
DEFAULT_PREFS = {}

PREF_MAP_CENTRE = "map_centre"
DEFAULT_PREFS[PREF_MAP_CENTRE] = (0, 0)

PREF_MAP_ZOOM = "map_zoom"
DEFAULT_PREFS[PREF_MAP_ZOOM] = 3

PREF_CACHE_TILELAYER = "cache_tilelayer"
DEFAULT_PREFS[PREF_CACHE_TILELAYER] = "/Users/dewey/Desktop/development/tmp/tilecache/%s/"

PREFS = DEFAULT_PREFS

OPENROLE_IMPORT = "open_import"
SAVEROLE_EXPORT = "save_export"
OPENROLE_GLOBAL = "open_global"
SAVEROLE_GLOBAL = "save_global"

TYPES_KMLORKMZ = "Google Earth KMZ File (*.kmz)\nGoogle Earth KML File (*.kml)"
TYPES_KMLANDKMZ = "Google Earth Files (*.kml; *.kmz)\nAll Files (*.*)"
TYPES_ALL = "All Files (*.*)"

TEMPFILES = []

def shellquote(s):
    return "'" + s.replace("'", "'\\''") + "'"

def launchfile(filename):
    if sys.platform.startswith("linux"):
        subprocess.call(["xdg-open", filename])
    elif sys.platform == 'win32':
        os.system('start %s' % shellquote(filename))
    elif sys.platform == 'darwin':
        os.system('open %s' % shellquote(filename))


class MainWindow(QMainWindow, Ui_MainWindow):
    
    def __init__(self, parent=None):
        super(MainWindow, self).__init__(parent)
        self.setupUi(self)
        self.restorePreferences()
        self.restoreWindowSettings()
        
        scaleFrame = ScaleOverlayMapFrame(SceneProjections.GOOGLE_MAPS)
        self.frame = scaleFrame.frame
        self.frame.setFrameShape(QFrame.StyledPanel)
        self.frame.setFrameShadow(QFrame.Sunken)
        self.frame.setCreateContextMenu(True)
        self.frame.setMouseTracking(True)
        self.frame.centreOnLatLon(PREFS[PREF_MAP_CENTRE])
        self.frame.setZoomLevel(PREFS[PREF_MAP_ZOOM])
        
        self.spinbox = QDoubleSpinBox()
        self.spinbox.setRange(0, self.frame.maxZoom())
        self.spinbox.setDecimals(2)
        self.spinbox.setSingleStep(0.05)
        self.spinbox.setValue(self.frame.zoomLevel())
        spintip = "Set Zoom"
        self.spinbox.setToolTip(spintip)
        self.spinbox.setStatusTip(spintip)
        
        self.layers = LayerManagerListWidget(LayerManager(self.frame))
        self.layerFactory = LayerFactory()
        self.layerFactory.addFactory(OpenStreetMapLayerFactory()).addFactory(ToporamaLayerFactory())
        self.activeLayers = []
        
        self.actionWindowLayers.setChecked(not self.layerDock.isHidden())
        
        self.measureDialog = MeasureDialog.MeasureDialog(self.frame, self)
        self.dataTableDialog = LayerDataDialog.LayerDataDialog(self)
        
        self.toolActions = (self.actionToolNone, self.actionToolMeasure, self.actionToolPan, self.actionToolSelect, self.actionToolZoomRect)
        self.layerContextActions = (self.actionLayerProperties, self.actionLayerRemove, 
                                    self.actionLayerExport, self.actionLayerImport, 
                                    self.actionLayerDataTable, self.actionLayerGEView,
                                    self.actionLayerRefresh, self.menuLayerTileZoom)
        
        self.connect(self.frame, SIGNAL("newCursorPosition(double, double)"), self.on_frame_newCursorPosition)
        self.connect(self.frame, SIGNAL("contextMenuRequested(QPoint, double, double)"), self.on_frame_contextMenuRequested)
        self.connect(self.frame, SIGNAL("measuredDistanceChanged(double, double, double)"), self.on_frame_measuredDistanceChanged)
        self.connect(self.frame, SIGNAL("measureComplete(double, double, double)"), self.on_frame_measureComplete)
        self.connect(self.frame, SIGNAL("newPoint(double, double)"), self.on_frame_newPoint)
        self.connect(self.frame, SIGNAL("newLineString"), self.on_frame_newLineString)
        self.connect(self.frame, SIGNAL("newPolygon"), self.on_frame_newPolygon)
        self.connect(self.frame, SIGNAL("boundsChanged()"), self.on_frame_boundsChanged)
        self.connect(self.frame, SIGNAL("projectionChanged()"), self.on_frame_projectionChanged)
        self.connect(self.frame, SIGNAL("toolChanged(int)"), self.on_frame_toolChanged)
        
        self.connect(self.spinbox, SIGNAL("valueChanged(double)"), self.frame.setZoomLevel)
        
        self.connect(self.layers, SIGNAL("layerContextMenuRequested(QPoint, QString)"), self.on_layers_layerContextMenuRequested)
        self.connect(self.layers, SIGNAL("layerDoubleClicked(QString)"), self.on_layers_layerDoubleClicked)
        self.connect(self.layers, SIGNAL("itemSelectionChanged()"), self.on_layers_itemSelectionChanged)
        
        self.connect(self.measureDialog, SIGNAL("showing(bool)"), self.actionWindowMeasure.setChecked)
        
        self.setCentralWidget(scaleFrame)
        self.toolBarZoom.addWidget(self.spinbox)
        self.layerDock.setWidget(self.layers)
    
    #==================================MAP SIGNALS===================================#
    
    def on_frame_toolChanged(self, toolInt):
        self.uncheckAllTools()
        if toolInt == GraphicsMapFrame.TOOL_NONE:
            self.actionToolNone.setChecked(True)
        elif toolInt == GraphicsMapFrame.TOOL_PAN:
            self.actionToolPan.setChecked(True)
        elif toolInt == GraphicsMapFrame.TOOL_SELECT:
            self.actionToolSelect.setChecked(True)
        elif toolInt == GraphicsMapFrame.TOOL_ZOOM_RECT:
            self.actionToolZoomRect.setChecked(True)
        elif toolInt == GraphicsMapFrame.TOOL_MEASURE:
            self.actionToolMeasure.setChecked(True)
            self.measureDialog.show()
        
        if toolInt != GraphicsMapFrame.TOOL_MEASURE and self.measureDialog.isVisible():
            self.measureDialog.close()
        
        
    
    def on_frame_newCursorPosition(self, lon, lat):
        self.statusbar.showMessage(self.stringLocation(lon, lat))
    
    def on_frame_measuredDistanceChanged(self, distance, perimeter, area):
        self.measureDialog.setValues((distance, perimeter, area))
    
    def on_frame_measureComplete(self, distance, perimeter, area):
        self.measureDialog.setValues((distance, perimeter, area))
    
    def on_frame_newPoint(self, lon, lat):
        #TODO:
        pass
    
    def on_frame_newLineString(self, *coordinates):
        #TODO:
        pass
    
    def on_frame_newPolygon(self, *coordinates):
        #TODO:
        pass
    
    def on_frame_mapClicked(self, lon, lat):
        #TODO:
        pass
    
    def on_frame_boundsChanged(self):
        self.spinbox.setValue(self.frame.zoomLevel())
        for layer in self.layers.layers():
            if layer.isSubTypeOf("MapFrameLayer|BitmapLayer|TiledBitmapLayer"):
                layer.loadImages()
    
    def on_frame_projectionChanged(self):
        #TODO:
        print "projection changed"
    
    def on_frame_contextMenuRequested(self, point, lon, lat):
        menu = QMenu(self)
        locAction = self.createAction(self.stringLocation(lon, lat))
        locAction.setEnabled(False)
        menu.addAction(locAction)
        menu.addSeparator()
        reverseGeocode = self.createAction("Reverse Geocode", lambda: self.on_mapcontext_reverseGeocode(lon, lat))
        menu.addAction(reverseGeocode)
        menu.exec_(point)

    
    #==================================MAP CONTEXT ACTIONS===================================#
    
    def on_mapcontext_reverseGeocode(self, lon, lat):
        #TODO:
        self.message("trying to reverse geocode %f, %f" % (lon, lat))
    
    #==================================MAP OPERATIONS===================================# 
    
    def stringLocation(self, lon, lat):
        #TODO implement based on preferences
        return str((lon, lat))
    
    #==================================LAYER MANAGER SIGNALS===================================#
   
    def on_layers_layerContextMenuRequested(self, point, layerId):
        self.menuLayers.exec_(point)
        
    def on_layers_layerDoubleClicked(self, layerId):
        self.on_actionLayerProperties_triggered()
    
    def on_layers_itemSelectionChanged(self):
        self.activeLayers = self.layers.selectedLayers()
        if len(self.activeLayers) == 1:
            for action in self.layerContextActions:
                action.setEnabled(True)
            istile = self.activeLayers[0].isSubTypeOf("MapFrameLayer|BitmapLayer|TiledBitmapLayer")
            self.actionLayerImport.setEnabled(not istile)
            self.menuLayerTileZoom.setEnabled(istile)
        elif len(self.activeLayers) >= 2:
            for action in self.layerContextActions:
                action.setEnabled(False)
            self.actionLayerGEView.setEnabled(True)
            self.actionLayerExport.setEnabled(True)
            self.actionLayerRemove.setEnabled(True)
        else:
            for action in self.layerContextActions:
                action.setEnabled(False)
    
    #===============================LAYER OPERATIONS=========================#
    
    def newLayer(self, typeString):
        nextId = self.layers.nextLayerId()
        layer = self.layerFactory.newLayer(typeString, nextId)
        if layer is not None:
            if layer.isSubTypeOf("MapFrameLayer|ItemizedPointLayer"):
                layer.setName("Point Layer")
                layer.setDefaultMarkerResource(":/map_azure.png")
                layer.setDefaultMarkerBind((0.5, 1))
            elif layer.isSubTypeOf("MapFrameLayer|BitmapLayer|TiledBitmapLayer"):
                layer.setName("Tiled Map Layer")
                directory = PREFS[PREF_CACHE_TILELAYER] % layer.tileType()
                if not os.path.exists(directory):
                    os.makedirs(directory)
                layer.setCacheDir(directory)
            elif layer.isSubTypeOf("MapFrameLayer|LineStringLayer"):
                layer.setName("Polyline Layer")
                layer.setIcon(":/ic_line.png")
            elif layer.isSubTypeOf("MapFrameLayer|PolygonLayer"):
                layer.setName("Polygon Layer")
                layer.setIcon(":/ic_polygon.png")
            else:
                layer.setName("New Layer")
            
            if len(self.activeLayers) == 1:
                newIndex = self.layers.newLayerIndexBySelection()
                self.layers.insert(layer, newIndex)
            else:
                self.layers.append(layer)
            self.layers.renameItem(nextId)
            
            if layer.isSubTypeOf("MapFrameLayer|BitmapLayer|TiledBitmapLayer"):
                layer.loadImages()
        else:
            self.error("Error adding layer: Could not create layer of type %s" % typeString)
    
    #==================================TOOLS MENU===================================#
    
    def uncheckAllTools(self, exceptTool=None):
        for toolAction in self.toolActions:
            if not toolAction is exceptTool:
                toolAction.setChecked(False)
    
    @pyqtSignature("bool")
    def on_actionToolNone_triggered(self, checked=True):
        """
        Slot documentation goes here.
        """
        self.frame.setTool(self.frame.TOOL_NONE)
        if not checked:
            self.actionToolNone.setChecked(True)
        
    
    @pyqtSignature("bool")
    def on_actionToolPan_triggered(self, checked):
        """
        Slot documentation goes here.
        """
        if checked:
            self.frame.setTool(self.frame.TOOL_PAN)
        else:
            self.on_actionToolNone_triggered()
            
    
    @pyqtSignature("bool")
    def on_actionToolSelect_triggered(self, checked):
        """
        Slot documentation goes here.
        """
        #TODO need to implement actual selection behaviour
        if checked:
            self.frame.setTool(self.frame.TOOL_SELECT)
        else:
            self.on_actionToolNone_triggered()
    
    @pyqtSignature("bool")
    def on_actionToolZoomRect_triggered(self, checked):
        """
        Slot documentation goes here.
        """
        if checked:
            self.frame.setTool(self.frame.TOOL_ZOOM_RECT)
        else:
            self.on_actionToolNone_triggered()
    
    @pyqtSignature("")
    def on_actionToolZoomIn_triggered(self):
        """
        Slot documentation goes here.
        """
        self.frame.zoomIn()
    
    @pyqtSignature("")
    def on_actionToolZoomOut_triggered(self):
        """
        Slot documentation goes here.
        """
        self.frame.zoomOut()
    
    @pyqtSignature("bool")
    def on_actionToolMeasure_triggered(self, checked):
        """
        Slot documentation goes here.
        """
        if checked:
            self.frame.setTool(self.frame.TOOL_MEASURE)
        else:
            self.on_actionToolNone_triggered()
    
    @pyqtSignature("bool")
    def on_actionToolSearch_triggered(self, checked):
        """
        Slot documentation goes here.
        """
        # TODO: not implemented yet
        print self.sender()
    
    #==================================EDIT MENU===================================#
    
    @pyqtSignature("")
    def on_actionEditCut_triggered(self):
        """
        Slot documentation goes here.
        """
        # TODO: not implemented yet
        print self.sender()
    
    @pyqtSignature("")
    def on_actionEditCopy_triggered(self):
        """
        Slot documentation goes here.
        """
        # TODO: not implemented yet
        print self.sender()
    
    @pyqtSignature("")
    def on_actionEditPaste_triggered(self):
        """
        Slot documentation goes here.
        """
        # TODO: not implemented yet
        print self.sender()
    
    @pyqtSignature("")
    def on_actionEditPreferences_triggered(self):
        """
        Slot documentation goes here.
        """
        # TODO: not implemented yet
        print self.sender()
    
    #==================================LAYER MENU===================================#
    
    @pyqtSignature("")
    def on_actionNewLayerPoint_triggered(self):
        """
        Slot documentation goes here.
        """
        self.newLayer("MapFrameLayer|ItemizedPointLayer")
    
    @pyqtSignature("")
    def on_actionNewLayerLine_triggered(self):
        """
        Slot documentation goes here.
        """
        self.newLayer("MapFrameLayer|LineStringLayer")
    
    @pyqtSignature("")
    def on_actionNewLayerPolygon_triggered(self):
        """
        Slot documentation goes here.
        """
        self.newLayer("MapFrameLayer|PolygonLayer")
    
    @pyqtSignature("")
    def on_actionNewLayerMapquest_triggered(self):
        """
        Slot documentation goes here.
        """
        self.newLayer("MapFrameLayer|BitmapLayer|TiledBitmapLayer|SlippyTileLayer|MapQuestLayer")
    
    @pyqtSignature("")
    def on_actionNewLayerToporama_triggered(self):
        """
        Slot documentation goes here.
        """
        self.newLayer("MapFrameLayer|BitmapLayer|TiledBitmapLayer|NTSTileLayer")
    
    @pyqtSignature("")
    def on_actionNewLayerOpenAerial_triggered(self):
        """
        Slot documentation goes here.
        """
        self.newLayer("MapFrameLayer|BitmapLayer|TiledBitmapLayer|SlippyTileLayer|MapQuestOpenAerialLayer")
    
    @pyqtSignature("")
    def on_actionNewLayerOSM_triggered(self):
        """
        Slot documentation goes here.
        """
        self.newLayer("MapFrameLayer|BitmapLayer|TiledBitmapLayer|SlippyTileLayer|OpenStreetMapLayer")
    
    @pyqtSignature("")
    def on_actionLayerRemove_triggered(self):
        """
        Slot documentation goes here.
        """
        if self.question("Remove %i layer(s) including unsaved data?" % len(self.activeLayers)):
            for layer in self.activeLayers:
                self.layers.removeById(layer.layerId())
        else:
            pass
    
    @pyqtSignature("")
    def on_actionLayerProperties_triggered(self):
        """
        Slot documentation goes here.
        """
        # TODO: not implemented yet
        print self.sender()
    
    @pyqtSignature("")
    def on_actionLayerDataTable_triggered(self):
        """
        Slot documentation goes here.
        """
        if len(self.activeLayers) == 1:
            self.dataTableDialog.setLayer(self.activeLayers[0])
            self.dataTableDialog.show()
        else:
            self.error("Can only pick one layer to view data")
        
    
    @pyqtSignature("")
    def on_actionLayerImport_triggered(self):
        """
        Slot documentation goes here.
        """
        if len(self.activeLayers) == 1:
            layer = self.activeLayers[0]
            fname = self.getfile(TYPES_KMLANDKMZ, OPENROLE_IMPORT)
            if fname:
                mapfileIO.parseToLayer(fname, layer)
                layer.recreateGraphicsItems()
                layer.zoomBounds()
        else:
            self.error("Can only pick one layer to import KML/KMZ")
        
    
    @pyqtSignature("")
    def on_actionLayerExport_triggered(self):
        """
        Slot documentation goes here.
        """
        
        fname = self.putfile(TYPES_KMLORKMZ, OPENROLE_IMPORT)
        if fname:
            try :
                resources = {}
                tmpdir = tempfile.mkdtemp()
                document = kml.KMLContainer(kml.KMLContainer.TAG_DOCUMENT)
                for layer in self.activeLayers:
                    if layer.isSubTypeOf("MapFrameLayer|BitmapLayer"):
                        folder = mapfileIO.bitmapLayerToFolder(layer, tmpdir, resources)
                    else:
                        folder = mapfileIO.layerToFolder(layer)
                    document.childobjs.append(folder)
                fileout = kml.KMLDocument(document)
                fileout.resources = resources
                
                if fname.endswith(".kml"):
                    kml.writeKML(fileout, fname)
                elif fname.endswith(".kmz"):
                    kml.writeKMZ(fileout, fname, resources)
                else:
                    self.error("Invalid File Type - choose .kml or .kmz")
            except mapfileIO.KMLConvertError, e:
                self.error("Error exporting to KML: %s" % e)
            except IOError, e:
                self.error("Error writing KML to disk: %s" % e)
            finally:
                kml.deleteresources(resources)
        
    @pyqtSignature("")
    def on_actionLayerGEView_triggered(self):
        """
        Slot documentation goes here.
        """
        
        fname = tempfile.mkstemp(".kmz")[1]
        TEMPFILES.append(fname)
        
        try :
            resources = {}
            tmpdir = tempfile.mkdtemp()
            document = kml.KMLContainer(kml.KMLContainer.TAG_DOCUMENT)
            for layer in self.activeLayers:
                if layer.isSubTypeOf("MapFrameLayer|BitmapLayer"):
                    folder = mapfileIO.bitmapLayerToFolder(layer, tmpdir, resources)
                else:
                    folder = mapfileIO.layerToFolder(layer)
                document.childobjs.append(folder)
            fileout = kml.KMLDocument(document)
            fileout.resources = resources
            kml.writeKMZ(fileout, fname, resources)
            launchfile(fname)
        except mapfileIO.KMLConvertError, e:
            self.error("Error exporting to KML: %s" % e)
        except IOError, e:
            self.error("Error writing KML to disk: %s" % e)
        finally:
            kml.deleteresources(resources)
    
    @pyqtSignature("")
    def on_actionLayerRefresh_triggered(self):
        """
        Slot documentation goes here.
        """
        if self.activeLayers:
            layer = self.activeLayers[0]
            if layer.isSubTypeOf("MapFrameLayer|BitmapLayer|TiledBitmapLayer"):
                layer.reloadImages()
            else:
                layer.recreateGraphicsItems()
    
    #==================================HELP MENU===================================#
    
    @pyqtSignature("")
    def on_actionHelpAbout_triggered(self):
        """
        Slot documentation goes here.
        """
        # TODO: not implemented yet
        print self.sender()
    
    @pyqtSignature("")
    def on_actionHelpDonate_triggered(self):
        """
        Slot documentation goes here.
        """
        # TODO: not implemented yet
        print self.sender()
    
    @pyqtSignature("")
    def on_actionHelpWebsite_triggered(self):
        """
        Slot documentation goes here.
        """
        # TODO: not implemented yet
        print self.sender()
    
    @pyqtSignature("")
    def on_actionHelpOnline_triggered(self):
        """
        Slot documentation goes here.
        """
        # TODO: not implemented yet
        print self.sender()
    
    #==================================FILE MENU===================================#
    
    @pyqtSignature("")
    def on_actionFileImport_triggered(self):
        """
        Slot documentation goes here.
        """
        # TODO: not implemented yet
        print self.sender()
    
    
    @pyqtSignature("")
    def on_actionFileNew_triggered(self):
        """
        Slot documentation goes here.
        """
        # TODO: not implemented yet
        print self.sender()
    
    @pyqtSignature("")
    def on_actionFileOpen_triggered(self):
        """
        Slot documentation goes here.
        """
        # TODO: not implemented yet
        print self.sender()
    
    @pyqtSignature("")
    def on_actionFileSave_triggered(self):
        """
        Slot documentation goes here.
        """
        # TODO: not implemented yet
        print self.sender()
    
    @pyqtSignature("")
    def on_actionFileSaveAs_triggered(self):
        """
        Slot documentation goes here.
        """
        # TODO: not implemented yet
        print self.sender()
    
    @pyqtSignature("")
    def on_actionFileQuit_triggered(self):
        """
        Slot documentation goes here.
        """
        self.close()
    
    @pyqtSignature("")
    def on_actionFilePrint_triggered(self):
        """
        Slot documentation goes here.
        """
        # TODO: not implemented yet
        print self.sender()
    
    @pyqtSignature("")
    def on_actionFileExport_triggered(self):
        """
        Slot documentation goes here.
        """
        # TODO: not implemented yet
        print self.sender()
    
    #==================================WINDOW MENU===================================#
    
    @pyqtSignature("")
    def on_actionWindowConsole_toggled(self, checked):
        """
        Slot documentation goes here.
        """
        # TODO: not implemented yet
        print self.sender()
    
    @pyqtSignature("bool")
    def on_actionWindowLayers_toggled(self, checked):
        """
        Slot documentation goes here.
        """
        self.layerDock.setHidden(not checked)
    
    @pyqtSignature("bool")
    def on_actionWindowMeasure_toggled(self, checked):
        """
        Slot documentation goes here.
        """
        if checked:
            self.measureDialog.show()
        else:
            self.measureDialog.close()

    #=======================UTILITY FUNCTIONS=========================#
    
    def createAction(self, text, slot=None, shortcut=None, iconRes=None, tip=None, checkable=False, signal="triggered()"):
        action = QAction(text, self)
        if iconRes is not None:
            action.setIcon(QIcon(iconRes))
        if shortcut is not None:
            action.setShortcut(shortcut)
        if tip is not None:
            action.setToolTip(tip)
            action.setStatusTip(tip)
        if slot is not None:
            self.connect(action, SIGNAL(signal), slot)
        if checkable:
            action.setCheckable(True)
        return action
    
    def error(self, message):
        QMessageBox.critical(self, QString("Error"), QString(message))
        
    def message(self, message):
        QMessageBox.information(self, QString("Error"), QString(message))
    
    def question(self, question):
        return QMessageBox.question(self, QString("Confirm"), QString(question), 
                                    buttons=QMessageBox.Yes|QMessageBox.No, 
                                    defaultButton=QMessageBox.NoButton) == QMessageBox.Yes
        
    def getfile(self, types, openrole):
        if openrole in PREFS:
            folder = PREFS[openrole]
        elif OPENROLE_GLOBAL in PREFS:
            folder = PREFS[OPENROLE_GLOBAL]
        else:
            folder = QString()
        
        fname = unicode(QFileDialog.getOpenFileName(self, "Choose File", folder, types))
        if fname:
            folder = os.path.dirname(fname)
            PREFS[openrole] = folder
        return fname
    
    def putfile(self, types, saverole):
        if saverole in PREFS:
            folder = PREFS[saverole]
        elif OPENROLE_GLOBAL in PREFS:
            folder = PREFS[SAVEROLE_GLOBAL]
        else:
            folder = QString()
        
        fname = unicode(QFileDialog.getSaveFileName(self, "Save File", folder, types))
        if fname:
            folder = os.path.dirname(fname)
            PREFS[saverole] = folder
        return fname
    
    #====================================PREFERENCE SAVING AND WHATNOT=================#
        
    def closeEvent(self, event):
        self.savePreferences()
        self.saveWindowSettings()
        if self.measureDialog.isVisible():
            self.measureDialog.close()
        for tfile in TEMPFILES:
            try:
                os.remove(tfile)
            except OSError:
                print "could not delete file %s" % tfile
    
    def restorePreferences(self):
        prefs = QSettings("UserPrefs")
        qvar = prefs.value("UserPrefs/PrefsDict", QVariant({}))
        tmpDict = qvar.toPyObject()
        for key, value in tmpDict.iteritems():
            if isinstance(value, QString):
                value = unicode(value)
            PREFS[str(key)] = value
        print PREFS
    
    def savePreferences(self):
        PREFS[PREF_MAP_CENTRE] = self.frame.centre()
        PREFS[PREF_MAP_ZOOM] = self.frame.zoomLevel()
        
        prefs = QSettings("UserPrefs")
        prefs.setValue("UserPrefs/PrefsDict", QVariant(PREFS))
        del prefs
        
    def restoreWindowSettings(self):
        settings = QSettings("MainWindow")
        size = settings.value("MainWindow/Size", QVariant(QSize(600, 500)))
        position = settings.value("MainWindow/Position", QVariant(QPoint(0, 0)))
        self.move(position.toPoint())
        self.resize(size.toSize())
        self.restoreState(settings.value("MainWindow/State").toByteArray())
    
    def saveWindowSettings(self):
        settings = QSettings("MainWindow")
        settings.setValue("MainWindow/Size", QVariant(self.size()))
        settings.setValue("MainWindow/Position", QVariant(self.pos()))
        settings.setValue("MainWindow/State", QVariant(self.saveState()))
        del settings